package com.suredy.app.porject.model;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.OrderBy;
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.DateTimeFormat.ISO;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.suredy.app.porject.constants.ContractOpLogType;
import com.suredy.app.porject.constants.ContractStatus;
import com.suredy.app.porject.constants.ContractType;
import com.suredy.app.porject.constants.FlowStatus;
import com.suredy.app.porject.constants.MoneyType;
import com.suredy.app.porject.constants.QuotationType;
import com.suredy.app.porject.constants.UserFileType;
import com.suredy.app.porject.model.sp.Money;
import com.suredy.core.model.BaseModel;
import com.suredy.security.entity.UserEntity;

/**
 * 合同模型
 * 
 * @author VIVID.G
 * @since 2015-10-15
 * @version v0.1
 */
@Entity
@Table(name = "tb_contract")
public class Contract extends BaseModel {

	private static final long serialVersionUID = 1L;

	@Column(name = "money_type", nullable = false, columnDefinition = "varchar(100) default 'TOTAL'")
	@Enumerated(EnumType.STRING)
	private QuotationType moneyType;

	/* 合同名称 */
	@Column(length = 500, nullable = false)
	private String name;

	/* 合同编号 */
	@Column(length = 100, nullable = false)
	private String no;

	/* 合同金额 */
	@Column(columnDefinition = "double(255,2) default 0.00")
	private Double price;

	/* 合同金额描述，适用于除总价之外的所有合同 */
	@Column(name = "price_des", length = 2000)
	private String priceDes;

	/* 办结日期 */
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	@Column(name = "bj_time")
	private Date bjTime;

	/* 合同起始工期 */
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	@Column(name = "contract_start")
	private Date contractStart;

	/* 合同结束工期 */
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	@Column(name = "contract_end")
	private Date contractEnd;

	/* 合同工期 */
	@Column(name = "contract_days")
	private Integer contractDays;

	/* 建设单位（甲方） */
	@Column(name = "company_a", length = 200, nullable = false)
	private String companyA;

	/* 承建单位（乙方） */
	@Column(name = "company_b", length = 200, nullable = false)
	private String companyB;

	/* 签约单位部门 */
	@Column(name = "customer_dep", length = 200)
	private String customerDep;

	/* 签约单位联系人 */
	@Column(name = "customer", length = 30)
	private String customer;

	/* 签约单位电话 */
	@Column(name = "customer_phone", length = 500)
	private String customerPhone;

	/* 合同起获方式 */
	@Column(name = "obtain_type", length = 100)
	private String obtainType;

	/* 负责人 */
	@Column(length = 500)
	private String manager;

	/* 项目负责人 */
	@JsonIgnore
	@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
	@JoinColumn(name = "xiangmu_header")
	private UserEntity xiangmuHeader;

	/* 技经负责人 */
	@JsonIgnore
	@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
	@JoinColumn(name = "jijing_header")
	private UserEntity jijingHeader;

	/* 结算方式 */
	@Column(name = "jiesuan_way", length = 2000)
	private String jiesuanWay;

	/* 付款方式 */
	@Column(name = "fukuan_way", length = 2000)
	private String fukuanWay;

	/* 结算金额 */
	@Column(name = "clearing_price", columnDefinition = "double(255,2) default 0.00")
	private Double clearingPrice;

	/* 实际起始日期 */
	@Column()
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private Date start;

	/* 实际结束日期 */
	@Column()
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private Date end;

	/* 开票情况 */
	@Column(name = "invoice_status", length = 20)
	private String invoiceStatus;

	/* 结算情况 */
	@Column(name = "clearing_status", length = 20)
	private String clearingStatus;

	/* 合同类型（收款合同/付款合同） */
	@Column(length = 30, nullable = false)
	@Enumerated(EnumType.STRING)
	private ContractType type;

	/* 合同状态（待建、在建、竣工、完工、中止） */
	@Column(length = 30, nullable = false)
	@Enumerated(EnumType.STRING)
	private ContractStatus status;

	/* 合同签订日期 */
	@Column(name = "sign_date", nullable = false)
	@DateTimeFormat(iso = ISO.DATE)
	private Date signDate;

	/* 备注 */
	@Column(length = 3000)
	private String remark;

	/* 合同主要内容 */
	@Column(name = "main_content", length = 3000)
	private String mainContent;

	/* 承保范围 */
	@Column(name = "chengbao_fanwei", length = 3000)
	private String chengbaoFanwei;

	/* 招标信息 */
	@JsonIgnore
	@OneToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
	@JoinColumn(name = "bid_id")
	private Bid bid;

	/* 资金情况 */
	@OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("gaveBack, time, name")
	private List<ContractMoney> money;

	/* 招标文件 */
	@OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("type, uploadTime, fileName")
	private List<ContractFile> files;

	/* 操作日志 */
	@OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("time DESC")
	private List<ContractOpLog> opLog;

	/* 父合同 */
	@JsonIgnore
	@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY)
	@JoinColumn(name = "parent_id")
	private Contract parent;

	/* 分包合同 */
	@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("type, no, contractEnd")
	private List<Contract> subContract;

	/* 工期计划 */
	@OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("completed, datePoint")
	private List<ContractWorkPlan> workPlans;

	/* 收款计划 */
	@OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("back, backTime")
	private List<ContractPayinPlan> payinPlans;

	/* 付款计划 */
	@OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("payout, payoutTime")
	private List<ContractPayoutPlan> payoutPlans;

	@OneToMany(mappedBy = "contract", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
	@Fetch(FetchMode.SUBSELECT)
	@OrderBy("time")
	private List<FlowOfContract2User> flowInfo;

	/* 流程当前环节 */
	@Column(name = "flow_status")
	@Enumerated(EnumType.STRING)
	private FlowStatus flowStatus;

	// for search properties
	@Transient
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private Date bjTimeStart;
	@Transient
	@DateTimeFormat(pattern = "yyyy-MM-dd")
	private Date bjTimeEnd;

	public QuotationType getMoneyType() {
		return moneyType;
	}

	public void setMoneyType(QuotationType moneyType) {
		this.moneyType = moneyType;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getNo() {
		return no;
	}

	public void setNo(String no) {
		this.no = no;
	}

	public Double getPrice() {
		return price;
	}

	public void setPrice(Double price) {
		this.price = price;
	}

	public String getPriceDes() {
		return priceDes;
	}

	public void setPriceDes(String priceDes) {
		this.priceDes = priceDes;
	}

	public Date getBjTime() {
		return bjTime;
	}

	public void setBjTime(Date bjTime) {
		this.bjTime = bjTime;
	}

	public Date getContractStart() {
		return contractStart;
	}

	public void setContractStart(Date contractStart) {
		this.contractStart = contractStart;
	}

	public Date getContractEnd() {
		return contractEnd;
	}

	public void setContractEnd(Date contractEnd) {
		this.contractEnd = contractEnd;
	}

	public Integer getContractDays() {
		return contractDays;
	}

	public void setContractDays(Integer contractDays) {
		this.contractDays = contractDays;
	}

	public String getCompanyA() {
		return companyA;
	}

	public void setCompanyA(String companyA) {
		this.companyA = companyA;
	}

	public String getCompanyB() {
		return companyB;
	}

	public void setCompanyB(String companyB) {
		this.companyB = companyB;
	}

	public String getCustomerDep() {
		return customerDep;
	}

	public void setCustomerDep(String customerDep) {
		this.customerDep = customerDep;
	}

	public String getCustomer() {
		return customer;
	}

	public void setCustomer(String customer) {
		this.customer = customer;
	}

	public String getCustomerPhone() {
		return customerPhone;
	}

	public void setCustomerPhone(String customerPhone) {
		this.customerPhone = customerPhone;
	}

	public String getObtainType() {
		return obtainType;
	}

	public void setObtainType(String obtainType) {
		this.obtainType = obtainType;
	}

	public String getManager() {
		return manager;
	}

	public void setManager(String manager) {
		this.manager = manager;
	}

	public UserEntity getXiangmuHeader() {
		return xiangmuHeader;
	}

	public void setXiangmuHeader(UserEntity xiangmuHeader) {
		this.xiangmuHeader = xiangmuHeader;
	}

	public UserEntity getJijingHeader() {
		return jijingHeader;
	}

	public void setJijingHeader(UserEntity jijingHeader) {
		this.jijingHeader = jijingHeader;
	}

	public String getJiesuanWay() {
		return jiesuanWay;
	}

	public void setJiesuanWay(String jiesuanWay) {
		this.jiesuanWay = jiesuanWay;
	}

	public String getFukuanWay() {
		return fukuanWay;
	}

	public void setFukuanWay(String fukuanWay) {
		this.fukuanWay = fukuanWay;
	}

	public Double getClearingPrice() {
		return clearingPrice;
	}

	public void setClearingPrice(Double clearingPrice) {
		this.clearingPrice = clearingPrice;
	}

	public Date getStart() {
		return start;
	}

	public void setStart(Date start) {
		this.start = start;
	}

	public Date getEnd() {
		return end;
	}

	public void setEnd(Date end) {
		this.end = end;
	}

	public String getInvoiceStatus() {
		return invoiceStatus;
	}

	public void setInvoiceStatus(String invoiceStatus) {
		this.invoiceStatus = invoiceStatus;
	}

	public String getClearingStatus() {
		return clearingStatus;
	}

	public void setClearingStatus(String clearingStatus) {
		this.clearingStatus = clearingStatus;
	}

	public ContractType getType() {
		return type;
	}

	public void setType(ContractType type) {
		this.type = type;
	}

	public ContractStatus getStatus() {
		return status;
	}

	public void setStatus(ContractStatus status) {
		this.status = status;
	}

	public Date getSignDate() {
		return signDate;
	}

	public void setSignDate(Date signDate) {
		this.signDate = signDate;
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

	public String getMainContent() {
		return mainContent;
	}

	public void setMainContent(String mainContent) {
		this.mainContent = mainContent;
	}

	public String getChengbaoFanwei() {
		return chengbaoFanwei;
	}

	public void setChengbaoFanwei(String chengbaoFanwei) {
		this.chengbaoFanwei = chengbaoFanwei;
	}

	public Bid getBid() {
		return bid;
	}

	public void setBid(Bid bid) {
		this.bid = bid;
	}

	public List<ContractMoney> getMoney() {
		return money;
	}

	public void setMoney(List<ContractMoney> money) {
		this.money = money;
	}

	public List<ContractFile> getFiles() {
		return files;
	}

	public void setFiles(List<ContractFile> files) {
		this.files = files;
	}

	public List<ContractOpLog> getOpLog() {
		return opLog;
	}

	public void setOpLog(List<ContractOpLog> opLog) {
		this.opLog = opLog;
	}

	public Contract getParent() {
		return parent;
	}

	public void setParent(Contract parent) {
		this.parent = parent;
	}

	public List<Contract> getSubContract() {
		return subContract;
	}

	public void setSubContract(List<Contract> subContract) {
		this.subContract = subContract;
	}

	public List<ContractWorkPlan> getWorkPlans() {
		return workPlans;
	}

	public void setWorkPlans(List<ContractWorkPlan> workPlans) {
		this.workPlans = workPlans;
	}

	public List<ContractPayinPlan> getPayinPlans() {
		return payinPlans;
	}

	public void setPayinPlans(List<ContractPayinPlan> payinPlans) {
		this.payinPlans = payinPlans;
	}

	public List<ContractPayoutPlan> getPayoutPlans() {
		return payoutPlans;
	}

	public void setPayoutPlans(List<ContractPayoutPlan> payoutPlans) {
		this.payoutPlans = payoutPlans;
	}

	public List<FlowOfContract2User> getFlowInfo() {
		return flowInfo;
	}

	public void setFlowInfo(List<FlowOfContract2User> flowInfo) {
		this.flowInfo = flowInfo;
	}

	public FlowStatus getFlowStatus() {
		return flowStatus;
	}

	public void setFlowStatus(FlowStatus flowStatus) {
		this.flowStatus = flowStatus;
	}

	public Date getBjTimeStart() {
		return bjTimeStart;
	}

	public void setBjTimeStart(Date bjTimeStart) {
		this.bjTimeStart = bjTimeStart;
	}

	public Date getBjTimeEnd() {
		return bjTimeEnd;
	}

	public void setBjTimeEnd(Date bjTimeEnd) {
		this.bjTimeEnd = bjTimeEnd;
	}

	// 以下是业务方法 //

	@Transient
	public ContractMoney getZbMoney() {
		if (this.getMoney() == null)
			return null;

		for (ContractMoney m : this.getMoney()) {
			if (MoneyType.C_ZB.getValue().equals(m.getName()))
				return m;
		}

		return null;
	}

	@Transient
	public ContractMoney getYfMoney() {
		if (this.getMoney() == null)
			return null;

		for (ContractMoney m : this.getMoney()) {
			if (MoneyType.C_YF.getValue().equals(m.getName()))
				return m;
		}

		return null;
	}

	@Transient
	public ContractMoney getLyMoney() {
		if (this.getMoney() == null)
			return null;

		for (ContractMoney m : this.getMoney()) {
			if (MoneyType.C_LY.getValue().equals(m.getName()))
				return m;
		}

		return null;
	}

	@Transient
	public ContractMoney getGzMoney() {
		if (this.getMoney() == null)
			return null;

		for (ContractMoney m : this.getMoney()) {
			if (MoneyType.C_GZ.getValue().equals(m.getName()))
				return m;
		}

		return null;
	}

	@Transient
	public ContractMoney getYfkMoney() {
		if (this.getMoney() == null)
			return null;

		for (ContractMoney m : this.getMoney()) {
			if (MoneyType.C_YFK.getValue().equals(m.getName()))
				return m;
		}

		return null;
	}

	@Transient
	public List<Money> getInMoney() {
		if (this.getMoney() == null)
			return null;

		List<Money> ret = new ArrayList<Money>();

		for (Money m : this.getMoney()) {
			if (m.getPayOut())
				continue;

			if (!m.getInAccount())
				continue;

			ret.add(m);
		}

		return ret.isEmpty() ? null : ret;
	}

	@Transient
	public List<Money> getOutMoney() {
		if (this.getMoney() == null)
			return null;

		List<Money> ret = new ArrayList<Money>();

		for (Money m : this.getMoney()) {
			if (!m.getPayOut())
				continue;

			if (!m.getInAccount())
				continue;

			ret.add(m);
		}

		return ret.isEmpty() ? null : ret;
	}

	@Transient
	public List<Money> getPlanInMoney() {
		if (this.getMoney() == null)
			return null;

		List<Money> ret = new ArrayList<Money>();

		for (Money m : this.getMoney()) {
			if (m.getPayOut())
				continue;

			if (m.getInAccount())
				continue;

			ret.add(m);
		}

		return ret.isEmpty() ? null : ret;
	}

	@Transient
	public double getInMoneyTotal() {
		if (this.getMoney() == null)
			return 0d;

		double ret = 0;

		for (Money m : this.getMoney()) {
			if (m.getPayOut())
				continue;

			// 未到账
			if (!m.getInAccount())
				continue;

			// 已退回
			if (Boolean.TRUE.equals(m.getGaveBack()))
				continue;

			ret += m.getTotal();
		}

		return ret;
	}

	@Transient
	public double getOutMoneyTotal() {
		if (this.getMoney() == null)
			return 0d;

		double ret = 0;

		for (Money m : this.getMoney()) {
			if (!m.getPayOut())
				continue;

			// 未到账
			if (!m.getInAccount())
				continue;

			// 已退回
			if (Boolean.TRUE.equals(m.getGaveBack()))
				continue;

			ret += m.getTotal();
		}

		return ret;
	}

	@Transient
	public double getPlanInMoneyTotal() {
		if (this.getPayinPlans() == null)
			return 0d;

		double ret = 0;

		for (ContractPayinPlan p : this.getPayinPlans()) {
			if (Boolean.TRUE.equals(p.getBack()))
				continue;

			ret += p.getTotal();
		}

		return ret;
	}

	@Transient
	public double getPlanoutMoneyTotal() {
		if (this.getPayoutPlans() == null)
			return 0d;

		double ret = 0;

		for (ContractPayoutPlan p : this.getPayoutPlans()) {
			if (Boolean.TRUE.equals(p.getPayout()))
				continue;

			ret += p.getTotal();
		}

		return ret;
	}

	@Transient
	public boolean isHasSubContract() {
		return this.getSubContract() != null && !this.getSubContract().isEmpty();
	}

	@Transient
	public List<Contract> getSubContracts() {
		if (this.getSubContract() == null || this.getSubContract().isEmpty())
			return null;

		List<Contract> ret = new ArrayList<Contract>();

		for (Contract sub : this.getSubContract()) {
			if (ContractType.AGREEMENT_CONTRACT.equals(sub.getType()))
				continue;

			ret.add(sub);
		}

		return ret.isEmpty() ? null : ret;
	}

	@Transient
	public List<Contract> getAgreementContracts() {
		if (this.getSubContract() == null || this.getSubContract().isEmpty())
			return null;

		List<Contract> ret = new ArrayList<Contract>();

		for (Contract sub : this.getSubContract()) {
			if (!ContractType.AGREEMENT_CONTRACT.equals(sub.getType()))
				continue;

			ret.add(sub);
		}

		return ret.isEmpty() ? null : ret;
	}

	@Transient
	public boolean isHasContractFile() {
		if (this.getFiles() == null || this.getFiles().isEmpty())
			return false;

		for (ContractFile file : this.getFiles()) {
			if (UserFileType.F200_CONTRACT_FILE.equals(file.getType()))
				return true;
		}

		return false;
	}

	/**
	 * 签约方
	 * 
	 * @return
	 */
	@Transient
	public String getQyf() {
		if (this.getType() == null)
			return null;

		return this.getType().isCollection() ? this.getCompanyA() : this.getCompanyB();
	}

	/**
	 * 实施方
	 * 
	 * @return
	 */
	@Transient
	public String getSsf() {
		if (this.getType() == null)
			return null;

		return this.getType().isCollection() ? this.getCompanyB() : this.getCompanyA();
	}

	/**
	 * 合同金额（万元）/降点%
	 * 
	 * @return
	 */
	@Transient
	public String getHtje() {
		if (this.getPrice() == null)
			return null;

		NumberFormat wy = new DecimalFormat("#,###.00");
		NumberFormat jd = new DecimalFormat("#,###.##");

		String ret = wy.format(this.getPrice());

		if (this.getBid() != null && QuotationType.DROP_POINT.equals(this.getBid().getEnumQuotationType()))
			ret += "（降点" + jd.format(this.getBid().getLastResult().getFinalMoney()) + "%）";

		return ret;

	}

	/**
	 * 合同履行状态
	 * 
	 * @return
	 */
	@Transient
	public String getLxzt() {
		if (this.getStatus() == null)
			return null;

		switch (this.getStatus()) {
			case START:
				return "履行中";
			case WAIT:
			case SUSPEND:
			case SHUTDOWN:
				return "未履行";
			case FINISH:
			case COMPLETED:
				return "完成";
		}

		return null;
	}

	/**
	 * 实施进度
	 * 
	 * @return
	 */
	@Transient
	public String getSsjd() {
		if (this.getStatus() == null)
			return null;

		switch (this.getStatus()) {
			case START:
				return "在建阶段";
			case FINISH:
				return "完工结算阶段";
			case COMPLETED:
				return "质保金阶段";
		}

		return null;
	}

	/**
	 * 收款金额
	 * 
	 * @return
	 */
	@Transient
	public Double getSkje() {
		if (this.getType() == null || !this.getType().isCollection())
			return null;

		return this.getInMoneyTotal();
	}

	/**
	 * 未收金额
	 * 
	 * @return
	 */
	@Transient
	public Double getWsje() {
		if (this.getType() == null || !this.getType().isCollection())
			return null;

		Double price = this.getPrice();
		if (price == null)
			price = 0d;

		Double js = this.getClearingPrice();
		if (js == null)
			js = price;

		return js - this.getSkje();
	}

	/**
	 * 总支金额
	 * 
	 * @return
	 */
	@Transient
	public double getZcje() {
		if (this.getType() == null)
			return 0;

		double ret = 0;

		// 收款合同（只统计费用支出）
		if (this.getType().isCollection()) {
			ret += this.getOutMoneyTotal();
		}

		// 付款合同（只统计结算金额）
		else {
			Double price = this.getPrice();
			if (price == null)
				price = 0d;

			Double js = this.getClearingPrice();
			if (js == null)
				js = price;

			ret += js;
		}

		List<Contract> sub = this.getSubContracts();

		if (sub == null || sub.isEmpty())
			return ret;

		// 付款子合同
		for (Contract s : sub) {
			ret += s.getZcje();
		}

		return ret;
	}

	/**
	 * 已支金额
	 * 
	 * @return
	 */
	@Transient
	public double getFkje() {
		double ret = this.getOutMoneyTotal();

		List<Contract> sub = this.getSubContracts();

		if (sub == null || sub.isEmpty())
			return ret;

		// 付款子合同
		for (Contract s : sub) {
			ret += s.getFkje();
		}

		return ret;
	}

	/**
	 * 未支金额
	 * 
	 * @return
	 */
	@Transient
	public double getWfje() {
		return this.getZcje() - this.getFkje();
	}

	/**
	 * 利润
	 * 
	 * @return
	 */
	@Transient
	public double getLr() {
		if (this.getType() == null)
			return 0;

		// 收款合同
		if (this.getType().isCollection()) {
			double zcje = this.getZcje(); // 总支金额

			Double price = this.getPrice();
			if (price == null)
				price = 0d;

			Double js = this.getClearingPrice();
			if (js == null)
				js = price;

			return js - zcje;
		}

		// 付款合同
		else {
			Double price = this.getPrice();
			if (price == null)
				price = 0d;

			Double js = this.getClearingPrice();
			if (js == null)
				js = price;

			return -js;
		}
	}

	/**
	 * 结算比率
	 * 
	 * @return
	 */
	@Transient
	public double getJsRatio() {
		Double price = this.getPrice();
		Double js = this.getClearingPrice(); // 结算金额

		price = price == null ? js : price;

		if (price == null)
			price = 1d;

		if (js == null)
			js = price;

		return js / price;
	}

	@Transient
	public Double getSkjeRatio() {
		Double skje = this.getSkje();
		if (skje == null)
			return null;

		Double price = this.getPrice();

		if (price == null)
			price = 1d;

		Double js = this.getClearingPrice(); // 结算金额
		if (js == null || js == 0d)
			js = price;

		return skje / js;
	}

	@Transient
	public Double getWsjeRatio() {
		Double wsje = this.getWsje();
		if (wsje == null)
			return null;

		Double price = this.getPrice();

		if (price == null)
			price = 1d;

		Double js = this.getClearingPrice(); // 结算金额
		if (js == null || js == 0d)
			js = price;

		return wsje / js;
	}

	@Transient
	public Double getZcjeRatio() {
		Double zcje = this.getZcje();
		if (zcje == null)
			return null;

		Double price = this.getPrice();

		if (price == null)
			price = 1d;

		Double js = this.getClearingPrice(); // 结算金额
		if (js == null || js == 0)
			js = price;

		return zcje / js;
	}

	@Transient
	public Double getFkjeRatio() {
		Double fkje = this.getFkje();
		if (fkje == null)
			return null;

		Double zcje = this.getZcje();
		if (zcje == null || zcje == 0d)
			zcje = 1d;

		return fkje / zcje;
	}

	@Transient
	public Double getWfjeRatio() {
		Double wfje = this.getWfje();
		if (wfje == null)
			return null;

		Double zcje = this.getZcje();
		if (zcje == null || zcje == 0d)
			zcje = 1d;

		return wfje / zcje;
	}

	@Transient
	public Double getLrRatio() {
		if (this.getType() == null)
			return null;

		// 总金额
		Double js = this.getClearingPrice();
		if (js == null)
			js = this.getPrice();

		if (js == null || js == 0)
			return null;

		return this.getLr() / js;
	}

	@Transient
	public boolean isFromBid() {
		if (this.getBid() == null || StringUtils.isBlank(bid.getId()))
			return false;

		return true;
	}

	/**
	 * 合同文件
	 * 
	 * @return
	 */
	@Transient
	public ContractFile getContractFile() {
		return this.getFileOfType(UserFileType.F200_CONTRACT_FILE);
	}

	/**
	 * 竣工资料
	 * 
	 * @return
	 */
	@Transient
	public ContractFile getJgFile() {
		return this.getFileOfType(UserFileType.F201_CONTRACT_COMPLETE_FILE);
	}

	/**
	 * 补充协议
	 * 
	 * @return
	 */
	@Transient
	public ContractFile getBcxyFile() {
		return this.getFileOfType(UserFileType.F202_CONTRACT_AGREEMENT_FILE);
	}

	/**
	 * 结算资料
	 * 
	 * @return
	 */
	@Transient
	public ContractFile getJszlFile() {
		return this.getFileOfType(UserFileType.F202_CONTRACT_CLOSE_MONEY);
	}

	/**
	 * 附件资料文件
	 * 
	 * @return
	 */
	@Transient
	public List<ContractFile> getOtherFiles() {
		if (this.getFiles() == null || this.getFiles().isEmpty())
			return null;

		List<ContractFile> ret = new ArrayList<ContractFile>();

		for (ContractFile f : this.getFiles()) {
			if (UserFileType.Z900_OTHER.equals(f.getType()))
				ret.add(f);
		}

		return ret.isEmpty() ? null : ret;
	}

	/**
	 * 判断资金是否可以被移除
	 * 
	 * @param name
	 * @return
	 */
	@Transient
	public boolean isPayoutMoneyCanBeRemove(String name) {
		if (StringUtils.isBlank(name))
			return false;

		MoneyType[] types = new MoneyType[] {MoneyType.C_ZB, MoneyType.C_YF, MoneyType.C_LY, MoneyType.C_GZ, MoneyType.C_YFK};

		for (MoneyType t : types) {
			if (name.equals(t.getValue()))
				return false;
		}

		return true;
	}

	@Transient
	public boolean isMainContract() {
		if (this.getType() == null)
			return false;

		return ArrayUtils.contains(ContractType.MAIN_CONTRACT_TYPES, this.getType());
	}

	@Transient
	public boolean isContractCompleted() {
		List<Contract> sub = this.getSubContracts();

		if (sub != null && !sub.isEmpty())
			for (Contract s : sub) {
				if (!s.isContractCompleted())
					return false;
			}

		return ContractStatus.COMPLETED.equals(this.getStatus());
	}

	@Transient
	public boolean isSubContractCompleted() {
		List<Contract> sub = this.getSubContracts();

		if (sub != null && !sub.isEmpty())
			for (Contract s : sub) {
				// 子合同没有完工
				if (!s.isSubContractCompleted())
					return false;

				// 自身没有完工
				if (!ContractStatus.COMPLETED.equals(s.getStatus()))
					return false;
			}

		return true;
	}

	@Transient
	public List<ContractOpLog> getProjecttimeChangeLog() {
		List<ContractOpLog> logs = this.getOpLog();

		if (logs == null || logs.isEmpty())
			return null;

		List<ContractOpLog> ret = new ArrayList<ContractOpLog>();

		for (ContractOpLog log : logs) {
			if (log == null)
				continue;

			if (log.getOp() == null)
				continue;

			if (ContractOpLogType.RESET_PROJECT_TIME.equals(log.getOp()))
				ret.add(log);
		}

		return ret.isEmpty() ? null : ret;
	}

	@Transient
	private ContractFile getFileOfType(UserFileType type) {
		if (this.getFiles() == null || this.getFiles().isEmpty())
			return null;

		if (type == null)
			return null;

		for (ContractFile f : this.getFiles()) {
			if (type.equals(f.getType()))
				return f;
		}

		return null;
	}

	@Transient
	public String getPriceString() {
		if (this.getMoneyType() == null)
			return "暂无报价！";

		String preffix = this.getMoneyType().getValue() + "：";

		switch (this.getMoneyType()) {
			case TOTAL:
				if (this.getPrice() == null)
					return preffix + "暂无报价";

				NumberFormat nf = new DecimalFormat("#,###.00元");

				return preffix + nf.format(this.getPrice());
			default:
				return preffix + this.getPriceDes();
		}
	}

	@Transient
	public boolean isThisCreator(String userId) {
		if (this.getFlowInfo() == null)
			return false;

		if (StringUtils.isBlank(userId))
			return false;

		for (FlowOfContract2User flow : this.getFlowInfo()) {
			if (flow == null || flow.getStatus() == null || flow.getUser() == null)
				continue;

			if (StringUtils.isBlank(flow.getUser().getId()))
				continue;

			// 必须处于新建环节
			if (!FlowStatus.FS2000_CONTRACT_TO_CREATE.equals(flow.getStatus()))
				continue;

			if (flow.getUser().getId().equals(userId))
				return true;
		}

		return false;
	}

}
